﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Mvc;
using CashOrCard.Models;
using CashOrCard.Extensions;
using CashOrCard.Helper;

namespace CashOrCard.Controllers
{
    public class PayPalController : Controller
    {
        //
        // GET: /PayPal/
        [CashOrCardAuthorizeExtension(AllowPermissions = "paypalprepaid_access", ErrorView = "PermissionDenied")]
        public ActionResult Index()
        {
            return View();
        }
        
        [HttpPost]
        [CashOrCardAuthorizeExtension(AllowPermissions = "paypalprepaid_access", ErrorView = "PermissionDenied")]
        public ActionResult Prepaid(string amount)
        {
            decimal dAmount = 0;
            decimal.TryParse(amount, out dAmount);
            if (dAmount <= 0)
            {
                return View("Index");
            }
            int userId = Common.CurrentUser.UserId;
            string userEmail = Common.CurrentUserEamil;
            string itemName = "Prepaid to Account";
            string itemDescription = "Prepaid $" + dAmount + " to account";
            string currency = ConfigurationManager.AppSettings["Currency"];
            int paypalId = 0;
            using (CashOrCardContext dbContext = new CashOrCardContext())
            {
                PaymentHistory payPalObj = new PaymentHistory();
                payPalObj.PaymentAmount = dAmount;
                payPalObj.Currency = currency;
                payPalObj.PaymentType = PaymentType.PrePaid.ToString();
                payPalObj.UserId = userId;
                payPalObj.UserEmail = userEmail;
                payPalObj.ItemName = itemName;
                payPalObj.PaymentComment = itemDescription;
                payPalObj.PaymentDate = DateTime.Now;
                dbContext.PaymentHistorys.Add(payPalObj);
                dbContext.SaveChanges();

                paypalId = payPalObj.PaymentId;
            }
            string paypalUrl = IsTestMode ? "https://www.sandbox.paypal.com/cgi-bin/webscr"
                : "https://www.paypal.com/cgi-bin/webscr";

            ViewBag.IsAutoSubmitForm = true;
            ViewBag.Amount = dAmount;
            ViewBag.OrderId = paypalId;
            ViewBag.ItemName = itemName;
            //ViewBag.ItemDescription = itemDescription;
            ViewBag.Currecy = currency;
            ViewBag.Email = userEmail;
            ViewBag.Business = ConfigurationManager.AppSettings["PaypalBusinessEmail"];
            ViewBag.SiteURL = ConfigurationManager.AppSettings["SiteURL"];
            ViewBag.PaypalURL = paypalUrl;
            return View();
        }

        public ActionResult Success()
        {
            return View();
        }

        public void IPN()
        {
            string pathString = ConfigurationManager.AppSettings["logPath"];
            System.IO.File.AppendAllText(pathString, "Start");
            var formVals = new Dictionary<string, string>();
            formVals.Add("cmd", "_notify-validate");

            string response = GetPayPalResponse(formVals, IsTestMode);
            System.IO.File.AppendAllText(pathString, response);
            if (response == "VERIFIED")
            {
                string transactionID = Request["txn_id"];
                string sAmountPaid = Request["mc_gross"];
                string orderID = Request["custom"];
                string paymentStatus = Request["payment_status"];
                string receiverEmail = Request["receiver_email"];
                string payerEmail = Request["payer_email"];

                //_logger.Info("IPN Verified for order " + orderID);
                if ("Completed".Equals(paymentStatus) && ConfigurationManager.AppSettings["PaypalBusinessEmail"].Equals(receiverEmail))
                {
                    using (CashOrCardContext dbContext = new CashOrCardContext())
                    {
                        PaymentHistory payPalObj = dbContext.PaymentHistorys.Find(int.Parse(orderID));
                        if (payPalObj != null && payPalObj.TransactionId != transactionID)
                        {
                            //validate the order
                            Decimal amountPaid = 0;
                            Decimal.TryParse(sAmountPaid, out amountPaid);
                            string paymentType = payPalObj.PaymentType;
                            int userId = payPalObj.UserId;
                            //check the amount paid
                            if (AmountPaidIsValid(payPalObj.PaymentAmount, amountPaid))
                            {
                                payPalObj.TransactionId = transactionID;
                                payPalObj.PaymentStatus = paymentStatus;
                                payPalObj.McGross = decimal.Parse(sAmountPaid);
                                payPalObj.McCurrency = Request["mc_currency"];
                                payPalObj.ReceiverEmail = receiverEmail;
                                payPalObj.PayerEmail = payerEmail;
                                payPalObj.FirstName = Request["first_name"];
                                payPalObj.LastName = Request["last_name"];
                                payPalObj.PaidDate = DateTime.Now;
                                payPalObj.PaymentResult = true;
                                dbContext.SaveChanges();

                                User userObj = dbContext.Users.Find(userId);
                                if (paymentType == PaymentType.Register.ToString())
                                {
                                    userObj.IsApproved = true;
                                    dbContext.SaveChanges();
                                }
                                else if (paymentType == PaymentType.PrePaid.ToString())
                                {
                                    userObj.Amount = userObj.Amount + amountPaid;
                                    dbContext.SaveChanges();
                                }
                            }
                        }
                    }
                }
            }
        }

        bool AmountPaidIsValid(decimal orderTotal, decimal amountPaid)
        {
            if (orderTotal != amountPaid)
            {
                //_logger.Warn("Invalid order amount to PDT/IPN: " + order.ID + "; Actual: " + amountPaid.ToString("C") + "; Should be: " + order.Total.ToString("C") + "user IP is " + Request.UserHostAddress);
                return false;
            }
            return true;
        }

        /// <summary>
        /// Utility method for handling PayPal Responses
        /// </summary>
        string GetPayPalResponse(Dictionary<string, string> formVals, bool useSandbox)
        {

            string paypalUrl = useSandbox ? "https://www.sandbox.paypal.com/cgi-bin/webscr"
                : "https://www.paypal.com/cgi-bin/webscr";


            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(paypalUrl);

            // Set values for the request back
            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";

            byte[] param = Request.BinaryRead(Request.ContentLength);
            string strRequest = Encoding.ASCII.GetString(param);

            StringBuilder sb = new StringBuilder();
            sb.Append(strRequest);

            foreach (string key in formVals.Keys)
            {
                sb.AppendFormat("&{0}={1}", key, formVals[key]);
            }
            strRequest += sb.ToString();
            req.ContentLength = strRequest.Length;

            //for proxy
            //WebProxy proxy = new WebProxy(new Uri("http://urlort#");
            //req.Proxy = proxy;
            //Send the request to PayPal and get the response
            string response = "";
            using (StreamWriter streamOut = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII))
            {

                streamOut.Write(strRequest);
                streamOut.Close();
                using (StreamReader streamIn = new StreamReader(req.GetResponse().GetResponseStream()))
                {
                    response = streamIn.ReadToEnd();
                }
            }

            return response;
        }

        private bool IsTestMode
        {
            get
            {
                bool isTest = false;
                bool.TryParse(ConfigurationManager.AppSettings["PaypalTestMode"], out isTest);
                return isTest;
            }
        }
    }
}
